package DocsExamples.Programming_with_documents.Working_with_document;

import DocsExamples.DocsExamplesBase;
import com.aspose.words.List;
import com.aspose.words.*;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.awt.*;
import java.text.MessageFormat;
import java.util.HashMap;

@Test
public class JoinAndAppendDocuments extends DocsExamplesBase {
    @Test
    public void simpleAppendDocument() throws Exception {
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Append the source document to the destination document using no extra options.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.SimpleAppendDocument.docx");
    }

    @Test
    public void appendDocument() throws Exception {
        //ExStart:AppendDocumentManually
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Loop through all sections in the source document.
        // Section nodes are immediate children of the Document node so we can just enumerate the Document.
        for (Section srcSection : srcDoc.getSections()) {
            // Because we are copying a section from one document to another, 
            // it is required to import the Section node into the destination document.
            // This adjusts any document-specific references to styles, lists, etc.
            //
            // Importing a node creates a copy of the original node, but the copy
            // ss ready to be inserted into the destination document.
            Node dstSection = dstDoc.importNode(srcSection, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);

            // Now the new section node can be appended to the destination document.
            dstDoc.appendChild(dstSection);
        }

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.AppendDocument.docx");
        //ExEnd:AppendDocumentManually
    }

    @Test
    public void appendDocumentToBlank() throws Exception {
        //ExStart:AppendDocumentToBlank
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document();

        // The destination document is not empty, often causing a blank page to appear before the appended document.
        // This is due to the base document having an empty section and the new document being started on the next page.
        // Remove all content from the destination document before appending.
        dstDoc.removeAllChildren();
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.AppendDocumentToBlank.docx");
        //ExEnd:AppendDocumentToBlank
    }

    @Test
    public void appendWithImportFormatOptions() throws Exception {
        //ExStart:AppendWithImportFormatOptions
        Document srcDoc = new Document(getMyDir() + "Document source with list.docx");
        Document dstDoc = new Document(getMyDir() + "Document destination with list.docx");

        // Specify that if numbering clashes in source and destination documents,
        // then numbering from the source document will be used.
        ImportFormatOptions options = new ImportFormatOptions();
        options.setKeepSourceNumbering(true);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES, options);
        //ExEnd:AppendWithImportFormatOptions
    }

    @Test
    public void convertNumPageFields() throws Exception {
        //ExStart:ConvertNumPageFields
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Restart the page numbering on the start of the source document.
        srcDoc.getFirstSection().getPageSetup().setRestartPageNumbering(true);
        srcDoc.getFirstSection().getPageSetup().setPageStartingNumber(1);

        // Append the source document to the end of the destination document.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        // After joining the documents the NUMPAGE fields will now display the total number of pages which
        // is undesired behavior. Call this method to fix them by replacing them with PAGEREF fields.
        convertNumPageFieldsToPageRef(dstDoc);

        // This needs to be called in order to update the new fields with page numbers.
        dstDoc.updatePageLayout();

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.ConvertNumPageFields.docx");
        //ExEnd:ConvertNumPageFields
    }

    //ExStart:ConvertNumPageFieldsToPageRef
    private void convertNumPageFieldsToPageRef(Document doc) throws Exception {
        // This is the prefix for each bookmark, which signals where page numbering restarts.
        // The underscore "_" at the start inserts this bookmark as hidden in MS Word.
        String bookmarkPrefix = "_SubDocumentEnd";
        String numpagesFieldName = "NUMPAGES";
        String pagerefFieldName = "PAGEREF";

        // Defines the number of page restarts encountered and, therefore,
        // the number of "sub" documents found within this document.
        int subDocumentCount = 0;

        DocumentBuilder builder = new DocumentBuilder(doc);

        for (Section section : doc.getSections()) {
            // This section has its page numbering restarted to treat this as the start of a sub-document.
            // Any PAGENUM fields in this inner document must be converted to special PAGEREF fields to correct numbering.
            if (section.getPageSetup().getRestartPageNumbering()) {
                // Don't do anything if this is the first section of the document.
                // This part of the code will insert the bookmark marking the end of the previous sub-document so,
                // therefore, it does not apply to the first section in the document.
                if (!section.equals(doc.getFirstSection())) {
                    // Get the previous section and the last node within the body of that section.
                    Section prevSection = (Section) section.getPreviousSibling();
                    Node lastNode = prevSection.getBody().getLastChild();

                    builder.moveTo(lastNode);

                    // This bookmark represents the end of the sub-document.
                    builder.startBookmark(bookmarkPrefix + subDocumentCount);
                    builder.endBookmark(bookmarkPrefix + subDocumentCount);

                    // Increase the sub-document count to insert the correct bookmarks.
                    subDocumentCount++;
                }
            }

            // The last section needs the ending bookmark to signal that it is the end of the current sub-document.
            if (section.equals(doc.getLastSection())) {
                // Insert the bookmark at the end of the body of the last section.
                // Don't increase the count this time as we are just marking the end of the document.
                Node lastNode = doc.getLastSection().getBody().getLastChild();

                builder.moveTo(lastNode);
                builder.startBookmark(bookmarkPrefix + subDocumentCount);
                builder.endBookmark(bookmarkPrefix + subDocumentCount);
            }

            // Iterate through each NUMPAGES field in the section and replace it with a PAGEREF field
            // referring to the bookmark of the current sub-document. This bookmark is positioned at the end
            // of the sub-document but does not exist yet. It is inserted when a section with restart page numbering
            // or the last section is encountered.
            Node[] nodes = section.getChildNodes(NodeType.FIELD_START, true).toArray();

            for (Node fieldStartNode : nodes) {
                FieldStart fieldStart = (FieldStart) fieldStartNode;

                if (fieldStart.getFieldType() == FieldType.FIELD_NUM_PAGES) {
                    String fieldCode = getFieldCode(fieldStart);
                    // Since the NUMPAGES field does not take any additional parameters,
                    // we can assume the field's remaining part. Code after the field name is the switches.
                    // We will use these to help recreate the NUMPAGES field as a PAGEREF field.
                    String fieldSwitches = fieldCode.replace(numpagesFieldName, "").trim();

                    // Inserting the new field directly at the FieldStart node of the original field will cause
                    // the new field not to pick up the original field's formatting. To counter this,
                    // insert the field just before the original field if a previous run cannot be found,
                    // we are forced to use the FieldStart node.
                    Node previousNode = (fieldStart.getPreviousSibling() != null ? fieldStart.getPreviousSibling() : fieldStart);

                    // Insert a PAGEREF field at the same position as the field.
                    builder.moveTo(previousNode);

                    Field newField = builder.insertField(
                            MessageFormat.format(" {0} {1}{2} {3} ", pagerefFieldName, bookmarkPrefix, subDocumentCount, fieldSwitches));

                    // The field will be inserted before the referenced node. Move the node before the field instead.
                    previousNode.getParentNode().insertBefore(previousNode, newField.getStart());

                    // Remove the original NUMPAGES field from the document.
                    removeField(fieldStart);
                }
            }
        }
    }
    //ExEnd:ConvertNumPageFieldsToPageRef

    //ExStart:GetRemoveField
    private void removeField(FieldStart fieldStart) {
        boolean isRemoving = true;

        Node currentNode = fieldStart;
        while (currentNode != null && isRemoving) {
            if (currentNode.getNodeType() == NodeType.FIELD_END)
                isRemoving = false;

            Node nextNode = currentNode.nextPreOrder(currentNode.getDocument());
            currentNode.remove();
            currentNode = nextNode;
        }
    }

    private String getFieldCode(FieldStart fieldStart) {
        StringBuilder builder = new StringBuilder();

        for (Node node = fieldStart;
             node != null && node.getNodeType() != NodeType.FIELD_SEPARATOR &&
                     node.getNodeType() != NodeType.FIELD_END;
             node = node.nextPreOrder(node.getDocument())) {
            // Use text only of Run nodes to avoid duplication.
            if (node.getNodeType() == NodeType.RUN)
                builder.append(node.getText());
        }

        return builder.toString();
    }
    //ExEnd:GetRemoveField

    @Test
    public void differentPageSetup() throws Exception {
        //ExStart:DifferentPageSetup
        //GistId:6e5c8fd2462c6d7ba26da4d9f66ff77b
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Set the source document to continue straight after the end of the destination document.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.CONTINUOUS);

        // Restart the page numbering on the start of the source document.
        srcDoc.getFirstSection().getPageSetup().setRestartPageNumbering(true);
        srcDoc.getFirstSection().getPageSetup().setPageStartingNumber(1);

        // To ensure this does not happen when the source document has different page setup settings, make sure the
        // settings are identical between the last section of the destination document.
        // If there are further continuous sections that follow on in the source document,
        // this will need to be repeated for those sections.
        srcDoc.getFirstSection().getPageSetup().setPageWidth(dstDoc.getLastSection().getPageSetup().getPageWidth());
        srcDoc.getFirstSection().getPageSetup().setPageHeight(dstDoc.getLastSection().getPageSetup().getPageHeight());
        srcDoc.getFirstSection().getPageSetup().setOrientation(dstDoc.getLastSection().getPageSetup().getOrientation());

        // Iterate through all sections in the source document.
        for (Paragraph para : (Iterable<Paragraph>) srcDoc.getChildNodes(NodeType.PARAGRAPH, true)) {
            para.getParagraphFormat().setKeepWithNext(true);
        }
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.DifferentPageSetup.docx");
        //ExEnd:DifferentPageSetup
    }

    @Test
    public void joinContinuous() throws Exception {
        //ExStart:JoinContinuous
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Make the document appear straight after the destination documents content.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.CONTINUOUS);
        // Append the source document using the original styles found in the source document.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.JoinContinuous.docx");
        //ExEnd:JoinContinuous
    }

    @Test
    public void joinNewPage() throws Exception {
        //ExStart:JoinNewPage
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Set the appended document to start on a new page.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.NEW_PAGE);
        // Append the source document using the original styles found in the source document.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.JoinNewPage.docx");
        //ExEnd:JoinNewPage
    }

    @Test
    public void keepSourceFormatting() throws Exception {
        //ExStart:KeepSourceFormatting
        //GistId:6e5c8fd2462c6d7ba26da4d9f66ff77b
        Document dstDoc = new Document();
        dstDoc.getFirstSection().getBody().appendParagraph("Destination document text. ");

        Document srcDoc = new Document();
        srcDoc.getFirstSection().getBody().appendParagraph("Source document text. ");
        // Append the source document to the destination document.
        // Pass format mode to retain the original formatting of the source document when importing it.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.KeepSourceFormatting.docx");
        //ExEnd:KeepSourceFormatting
    }

    @Test
    public void keepSourceTogether() throws Exception {
        //ExStart:KeepSourceTogether
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Document destination with list.docx");

        // Set the source document to appear straight after the destination document's content.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.CONTINUOUS);

        for (Paragraph para : (Iterable<Paragraph>) srcDoc.getChildNodes(NodeType.PARAGRAPH, true)) {
            para.getParagraphFormat().setKeepWithNext(true);
        }
        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.KeepSourceTogether.docx");
        //ExEnd:KeepSourceTogether
    }

    @Test
    public void listKeepSourceFormatting() throws Exception {
        //ExStart:ListKeepSourceFormatting
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Document destination with list.docx");

        // Append the content of the document so it flows continuously.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.CONTINUOUS);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.ListKeepSourceFormatting.docx");
        //ExEnd:ListKeepSourceFormatting
    }

    @Test
    public void listUseDestinationStyles() throws Exception {
        //ExStart:ListUseDestinationStyles
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Document destination with list.docx");

        // Set the source document to continue straight after the end of the destination document.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.CONTINUOUS);

        // Keep track of the lists that are created.
        HashMap<Integer, List> newLists = new HashMap<>();

        for (Paragraph para : (Iterable<Paragraph>) srcDoc.getChildNodes(NodeType.PARAGRAPH, true)) {
            if (para.isListItem()) {
                int listId = para.getListFormat().getList().getListId();

                // Check if the destination document contains a list with this ID already. If it does, then this may
                // cause the two lists to run together. Create a copy of the list in the source document instead.
                if (dstDoc.getLists().getListByListId(listId) != null) {
                    List currentList;
                    // A newly copied list already exists for this ID, retrieve the stored list,
                    // and use it on the current paragraph.
                    if (newLists.containsKey(listId)) {
                        currentList = newLists.get(listId);
                    } else {
                        // Add a copy of this list to the document and store it for later reference.
                        currentList = srcDoc.getLists().addCopy(para.getListFormat().getList());
                        newLists.put(listId, currentList);
                    }

                    // Set the list of this paragraph to the copied list.
                    para.getListFormat().setList(currentList);
                }
            }
        }

        // Append the source document to end of the destination document.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.ListUseDestinationStyles.docx");
        //ExEnd:ListUseDestinationStyles
    }

    @Test
    public void restartPageNumbering() throws Exception {
        //ExStart:RestartPageNumbering
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.NEW_PAGE);
        srcDoc.getFirstSection().getPageSetup().setRestartPageNumbering(true);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.RestartPageNumbering.docx");
        //ExEnd:RestartPageNumbering
    }

    @Test
    public void updatePageLayout() throws Exception {
        //ExStart:UpdatePageLayout
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // If the destination document is rendered to PDF, image etc.
        // or UpdatePageLayout is called before the source document. Is appended,
        // then any changes made after will not be reflected in the rendered output
        dstDoc.updatePageLayout();

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        // For the changes to be updated to rendered output, UpdatePageLayout must be called again.
        // If not called again, the appended document will not appear in the output of the next rendering.
        dstDoc.updatePageLayout();

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.UpdatePageLayout.docx");
        //ExEnd:UpdatePageLayout
    }

    @Test
    public void useDestinationStyles() throws Exception {
        //ExStart:UseDestinationStyles
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Append the source document using the styles of the destination document.
        dstDoc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.UseDestinationStyles.docx");
        //ExEnd:UseDestinationStyles
    }

    @Test
    public void smartStyleBehavior() throws Exception {
        //ExStart:SmartStyleBehavior
        Document dstDoc = new Document();
        DocumentBuilder builder = new DocumentBuilder(dstDoc);

        Style myStyle = builder.getDocument().getStyles().add(StyleType.PARAGRAPH, "MyStyle");
        myStyle.getFont().setSize(14.0);
        myStyle.getFont().setName("Courier New");
        myStyle.getFont().setColor(Color.BLUE);

        builder.getParagraphFormat().setStyleName(myStyle.getName());
        builder.writeln("Hello world!");

        // Clone the document and edit the clone's "MyStyle" style, so it is a different color than that of the original.
        // If we insert the clone into the original document, the two styles with the same name will cause a clash.
        Document srcDoc = dstDoc.deepClone();
        srcDoc.getStyles().get("MyStyle").getFont().setColor(Color.RED);

        // When we enable SmartStyleBehavior and use the KeepSourceFormatting import format mode,
        // Aspose.Words will resolve style clashes by converting source document styles.
        // with the same names as destination styles into direct paragraph attributes.
        ImportFormatOptions options = new ImportFormatOptions();
        options.setSmartStyleBehavior(true);

        builder.insertDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, options);

        builder.getDocument().save(getArtifactsDir() + "JoinAndAppendDocuments.SmartStyleBehavior.docx");
        //ExEnd:SmartStyleBehavior
    }

    @Test
    public void insertDocument() throws Exception {
        //ExStart:InsertDocumentWithBuilder
        //GistId:6e5c8fd2462c6d7ba26da4d9f66ff77b
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");
        DocumentBuilder builder = new DocumentBuilder(dstDoc);

        builder.moveToDocumentEnd();
        builder.insertBreak(BreakType.PAGE_BREAK);

        builder.insertDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);
        builder.getDocument().save(getArtifactsDir() + "JoinAndAppendDocuments.insertDocument.docx");
        //ExEnd:InsertDocumentWithBuilder
    }

    @Test
    public void insertDocumentInline() throws Exception {
        //ExStart:InsertDocumentInlineWithBuilder
        //GistId:6e5c8fd2462c6d7ba26da4d9f66ff77b
        DocumentBuilder srcDoc = new DocumentBuilder();
        srcDoc.write("[src content]");

        // Create destination document.
        DocumentBuilder dstDoc = new DocumentBuilder();
        dstDoc.write("Before ");
        dstDoc.insertNode(new BookmarkStart(dstDoc.getDocument(), "src_place"));
        dstDoc.insertNode(new BookmarkEnd(dstDoc.getDocument(), "src_place"));
        dstDoc.write(" after");

        Assert.assertEquals("Before  after", dstDoc.getDocument().getText().trim());

        // Insert source document into destination inline.
        dstDoc.moveToBookmark("src_place");
        dstDoc.insertDocumentInline(srcDoc.getDocument(), ImportFormatMode.USE_DESTINATION_STYLES, new ImportFormatOptions());

        Assert.assertEquals("Before [src content] after", dstDoc.getDocument().getText().trim());
        //ExEnd:InsertDocumentInlineWithBuilder
    }

    @Test
    public void keepSourceNumbering() throws Exception {
        //ExStart:KeepSourceNumbering
        Document srcDoc = new Document(getMyDir() + "List source.docx");
        Document dstDoc = new Document(getMyDir() + "List destination.docx");

        ImportFormatOptions options = new ImportFormatOptions();
        // If there is a clash of list styles, apply the list format of the source document.
        // Set the "KeepSourceNumbering" property to "false" to not import any list numbers into the destination document.
        // Set the "KeepSourceNumbering" property to "true" import all clashing
        // list style numbering with the same appearance that it had in the source document.
        options.setKeepSourceNumbering(true);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, options);
        dstDoc.updateListLabels();

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.KeepSourceNumbering.docx");
        //ExEnd:KeepSourceNumbering
    }

    @Test
    public void ignoreTextBoxes() throws Exception {
        //ExStart:IgnoreTextBoxes
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Keep the source text boxes formatting when importing.
        ImportFormatOptions importFormatOptions = new ImportFormatOptions();
        importFormatOptions.setIgnoreTextBoxes(false);

        NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING,
                importFormatOptions);

        ParagraphCollection srcParas = srcDoc.getFirstSection().getBody().getParagraphs();
        for (Paragraph srcPara : srcParas) {
            Node importedNode = importer.importNode(srcPara, true);
            dstDoc.getFirstSection().getBody().appendChild(importedNode);
        }

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.IgnoreTextBoxes.docx");
        //ExEnd:IgnoreTextBoxes
    }

    @Test
    public void ignoreHeaderFooter() throws Exception {
        //ExStart:IgnoreHeaderFooter
        Document srcDocument = new Document(getMyDir() + "Document source.docx");
        Document dstDocument = new Document(getMyDir() + "Northwind traders.docx");

        ImportFormatOptions importFormatOptions = new ImportFormatOptions();
        importFormatOptions.setIgnoreHeaderFooter(false);

        dstDocument.appendDocument(srcDocument, ImportFormatMode.KEEP_SOURCE_FORMATTING, importFormatOptions);

        dstDocument.save(getArtifactsDir() + "JoinAndAppendDocuments.IgnoreHeaderFooter.docx");
        //ExEnd:IgnoreHeaderFooter
    }

    @Test
    public void linkHeadersFooters() throws Exception {
        //ExStart:LinkHeadersFooters
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Set the appended document to appear on a new page.
        srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.NEW_PAGE);
        // Link the headers and footers in the source document to the previous section.
        // This will override any headers or footers already found in the source document.
        srcDoc.getFirstSection().getHeadersFooters().linkToPrevious(true);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.LinkHeadersFooters.docx");
        //ExEnd:LinkHeadersFooters
    }

    @Test
    public void removeSourceHeadersFooters() throws Exception {
        //ExStart:RemoveSourceHeadersFooters
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Remove the headers and footers from each of the sections in the source document.
        for (Section section : (Iterable<Section>) srcDoc.getSections()) {
            section.clearHeadersFooters();
        }

        // Even after the headers and footers are cleared from the source document, the "LinkToPrevious" setting 
        // for HeadersFooters can still be set. This will cause the headers and footers to continue from the destination 
        // document. This should set to false to avoid this behavior.
        srcDoc.getFirstSection().getHeadersFooters().linkToPrevious(false);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.RemoveSourceHeadersFooters.docx");
        //ExEnd:RemoveSourceHeadersFooters
    }

    @Test
    public void unlinkHeadersFooters() throws Exception {
        //ExStart:UnlinkHeadersFooters
        Document srcDoc = new Document(getMyDir() + "Document source.docx");
        Document dstDoc = new Document(getMyDir() + "Northwind traders.docx");

        // Unlink the headers and footers in the source document to stop this
        // from continuing the destination document's headers and footers.
        srcDoc.getFirstSection().getHeadersFooters().linkToPrevious(false);

        dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

        dstDoc.save(getArtifactsDir() + "JoinAndAppendDocuments.UnlinkHeadersFooters.docx");
        //ExEnd:UnlinkHeadersFooters
    }
}
